home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / plan / src / time.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  8KB  |  289 lines

  1. /*
  2.  * Convert date and time data formats.
  3.  *
  4.  *    tm_to_time(tm)        convert tm struct to seconds since 1/1/70
  5.  *    time_to_tm(tp)        convert seconds since 1/1/70 to tm struct
  6.  *    get_time()        return current time in seconds since 1/1/70
  7.  *    set_tzone()        figure out current timezone (config.tzone)
  8.  */
  9.  
  10. #include <stdio.h>
  11. #if defined(MIPS) || defined(NEWSOS4)
  12. #include <sys/types.h>
  13. #endif
  14. #include <time.h>
  15. #include <X11/StringDefs.h>
  16. #include "conf.h"
  17.  
  18. #undef DEBUG            /* define this to debug timezone calc */
  19.  
  20. extern char        *getenv();
  21. extern void        get_rsrc();
  22. extern struct config    config;        /* global configuration data */
  23.  
  24. short monthlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  25. short monthbegin[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  26.  
  27.  
  28. /*
  29.  * convert a tm structure (d.m.y h:m:s) to a time in seconds since 1/1/70.
  30.  * The difference to mktime() is that the result modulo 86400 is always
  31.  * the time, regardless of timezones and daylight saving time. This makes
  32.  * it much easier to process days with different DST status.
  33.  * This routine only works correctly for the range 1970..2069.
  34.  */
  35.  
  36. time_t tm_to_time(tm)
  37.     struct tm        *tm;        /* time/date to convert */
  38. {
  39.     time_t            t;        /* return value */
  40.  
  41.     t  = monthbegin[tm->tm_mon]            /* full months */
  42.        + tm->tm_mday-1                /* full days */
  43.        + (!(tm->tm_year & 3) && tm->tm_mon > 1);    /* leap day this year*/
  44.     tm->tm_yday = t;
  45.     t += 365 * (tm->tm_year - 70)            /* full years */
  46.        + (tm->tm_year - 69)/4;            /* past leap days */
  47.     tm->tm_wday = (t + 4) % 7;
  48.  
  49.     t = t*86400 + tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec;
  50.     if (tm->tm_mday > monthlen[tm->tm_mon] +
  51.               (!(tm->tm_year & 3) && tm->tm_mon == 1))
  52.         return((time_t)-1);
  53.     return(t);
  54. }
  55.  
  56.  
  57. /*
  58.  * convert time in seconds since 1/1/70 to a tm structure, and also fill in
  59.  * the week number, julian date, and weekday. The difference to localtime()
  60.  * is that timezones and daylight saving time are ignored.
  61.  * This routine only works correctly for the range 1970..2069.
  62.  */
  63.  
  64. struct tm *time_to_tm(t)
  65.     time_t            t;        /* time to convert */
  66. {
  67.     int            n, l;        /* temp */
  68.     static struct tm    tm;        /* returned tm */
  69.  
  70.     tm.tm_sec  = t % 60;        t /= 60;
  71.     tm.tm_min  = t % 60;        t /= 60;
  72.     tm.tm_hour = t % 24;        t /= 24;
  73.     tm.tm_wday = (t + 4) % 7;
  74.  
  75.     n = t / (365+365+366+365);
  76.     tm.tm_year = 70 + n*4;        t -= n * (365+365+366+365);
  77.     if (t > 364)    tm.tm_year++,    t -= 365;
  78.     if (t > 364)    tm.tm_year++,    t -= 365;
  79.     if (t > 365)    tm.tm_year++,    t -= 366;
  80.     tm.tm_yday = t;
  81.  
  82.     for (n=0; n < 11; n++) {
  83.         l = monthlen[n] + (n==1 && !(tm.tm_year&3));
  84.         if (t < l)
  85.             break;
  86.         t -= l;
  87.     }
  88.     tm.tm_mon  = n;
  89.     tm.tm_mday = t+1;
  90.     return(&tm);
  91. }
  92.  
  93.  
  94. /*
  95.  * return current time in seconds since 1/1/70. The timezone is applied
  96.  * such that the return value modulo 86400 is the number of seconds since
  97.  * midnight.
  98.  */
  99.  
  100. time_t get_time()
  101. {
  102.     return(time(0) - config.tzone + config.adjust_time);
  103. }
  104.  
  105.  
  106. /*
  107.  * return the current time zone as the number of seconds as difference
  108.  * to GMT (UTC) in seconds. Since all the tricks with tm_isdst, gmtoff,
  109.  * _timezone etc turned out to be nonportable, I am now parsing the TZ
  110.  * environment variable directly. There is nothing standard about standard
  111.  * libraries when it comes to time calculation!
  112.  */
  113.  
  114. void set_tzone()
  115. {
  116.     register struct config *c = &config;
  117.     time_t        now;            /* current local time */
  118.     time_t        tod;            /* time-of-day, 0..86399 */
  119.     struct tm    *tm;            /* julian date of <now> */
  120.  
  121.     now = time(0) - c->raw_tzone;
  122.     tod = now % 86400;
  123.     tm = time_to_tm(now);
  124.     switch(c->dst_flag) {
  125.       case 0:                    /* dst on */
  126.         c->tzone = c->raw_tzone - 3600;
  127.         break;
  128.       case 1:                    /* dst off */
  129.         c->tzone = c->raw_tzone;
  130.         break;
  131.       case 2:                    /* auto dst */
  132.         if ((tm->tm_yday >  c->dst_begin                 ||
  133.              tm->tm_yday == c->dst_begin && tod >= c->dst_begin_time)&&
  134.             (tm->tm_yday == c->dst_end   && tod <  c->dst_end_time   ||
  135.              tm->tm_yday <  c->dst_end))
  136.             c->tzone = c->raw_tzone - 3600;
  137.         else
  138.             c->tzone = c->raw_tzone;
  139.     }
  140. }
  141.  
  142.  
  143. /*
  144.  * Figure out reasonable values for the config fields raw_tzone, dst_flag,
  145.  * dst_begin, and dst_end. This is used for defaults if the .dayplan file
  146.  * does not specify the adjustment, or when the user presses Guess in the
  147.  * Adjust Time popup.
  148.  */
  149.  
  150. #define DST_BEGIN    64            /* default begin of DST */
  151. #define DST_END        220            /* default end of DST */
  152.  
  153. #ifdef DEBUG
  154. static char *zone_time_string();
  155. #endif
  156. static get_zone_time();
  157.  
  158. guess_tzone()
  159. {
  160.     char        *tz=0;            /* timezone string (TZ) */
  161.     int        zone=0, dst= -3600;    /* difference from GMT */
  162.     int        begin=0, begintime=0;    /* dst begin: julian day/time*/
  163.     int        end=0,   endtime=0;    /* dst end: julian day/time */
  164.  
  165.     if (((tz = getenv("PLAN_TZ")) && *tz ||
  166.          (tz = getenv("TZ"))      && *tz) && strrchr("0123456789-",tz[3])){
  167.         do {
  168.             if (!*tz++ || !*tz++ || !*tz++)        /* MET */
  169.                 break;
  170.             zone = get_zone_time(&tz, 0);        /* time */
  171.             dst  = zone - 3600;
  172.             if (!*tz++ || !*tz++ || !*tz++)        /* MST */
  173.                 break;
  174.             dst = get_zone_time(&tz, dst);        /* time */
  175.             if (*tz++ != ';')            /* ;begin */
  176.                 break;
  177.             while (*tz >= '0' && *tz <= '9')
  178.                 begin = begin*10 + *tz++ - '0';
  179.             if (*tz == '/') {            /*    /time */
  180.                 tz++;
  181.                 begintime = get_zone_time(&tz, 0);
  182.             }
  183.             if (*tz++ != ',')            /* ,end */
  184.                 break;
  185.             while (*tz >= '0' && *tz <= '9')
  186.                 end = end*10 + *tz++ - '0';
  187.             if (*tz++ == '/')            /*    /time */
  188.                 endtime = get_zone_time(&tz, 0);
  189.         } while (0);
  190.     } else {
  191. #if defined(SVR4) || defined(SOLARIS2)
  192.         time_t now = get_time();
  193.         struct tm *tm = localtime(&now);
  194.         time_t h = tm->tm_hour;
  195.         struct tm *gmt = gmtime(&now);
  196.         zone = (gmt->tm_hour - h) * 3600;
  197.         dst  = zone - 3600;
  198. #else
  199. #if defined(bsdi) || defined(SUN) || defined(SVR4)
  200.         time_t now;
  201.         struct tm *tm;
  202.         tzset();
  203.         now = time(0);
  204.         tm = localtime(&now);
  205.         zone = -tm->tm_gmtoff;
  206. #endif
  207. #endif
  208.     }
  209. #ifdef DEBUG
  210.     if (tz = getenv("PLAN_TZ"))
  211.         printf("PLAN_TZ env variable: %s\n", tz);
  212.     if (tz = getenv("TZ"))
  213.         printf("TZ env variable:      %s\n", tz);
  214.     printf("standard timezone:    GMT%s\n", zone_time_string(zone));
  215.     printf("DST timezone:         GMT%s\n", zone_time_string(dst));
  216.     printf("DST start:            %s on julian day %d\n",
  217.                     zone_time_string(begintime)+1, begin);
  218.     printf("DST end:              %s on julian day %d\n",
  219.                     zone_time_string(endtime)+1, end);
  220. #endif
  221.     if (!begin) {                        /* defaults */
  222.         begin     = DST_BEGIN;
  223.         begintime = 2*3600;
  224.     }
  225.     if (!end) {
  226.         end       = DST_END;
  227.         endtime   = 2*3600;
  228.     }
  229.     config.raw_tzone      = zone;
  230.     config.dst_flag       = 2;
  231.     config.dst_begin      = begin;
  232.     config.dst_end        = end;
  233.     config.dst_begin_time = begintime;
  234.     config.dst_end_time   = endtime;
  235. #ifdef DEBUG
  236.     printf("current timezone:  GMT%s\n", zone_time_string(zone));
  237. #endif
  238. }
  239.  
  240.  
  241. /*
  242.  * parse a time string of the form [hours[:minutes[:seconds]]], return seconds
  243.  */
  244.  
  245. static get_zone_time(tzp, zdefault)
  246.     char        **tzp;
  247.     int        zdefault;
  248. {
  249.     char        *tz = *tzp;
  250.     int        i, num, zone = 0;
  251.     int        sign = 1;
  252.  
  253.     if (*tz == '-') tz++, sign = -1;
  254.     if (*tz == '+') tz++;
  255.     for (i=0; i < 3; i++) {
  256.         zone *= 60;
  257.         num = 0;
  258.         while (*tz >= '0' && *tz <= '9')
  259.             num = num*10 + *tz++ - '0';
  260.         zone += num;
  261.         tz += *tz == ':';
  262.     }
  263.     zone *= sign;
  264.     if (tz == *tzp)
  265.         zone = zdefault;
  266.     *tzp = tz;
  267.     return(zone);
  268. }
  269.  
  270.  
  271. /*
  272.  * return a number of seconds as a string "+/-hours:minutes:seconds"
  273.  */
  274.  
  275. #ifdef DEBUG
  276. static char *zone_time_string(t)
  277.     int        t;
  278. {
  279.     static char buf[12];
  280.  
  281.     t %= 86400;
  282.     buf[0] = t < 0 ? '-' : '+';
  283.     if (t < 0)
  284.         t = -t;
  285.     sprintf(buf+1, "%02d:%02d:%02d", t/3600, (t/60)%60, t%60);
  286.     return(buf);
  287. }
  288. #endif
  289.